package com.xkcyy.one.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xkcyy.one.entity.Agent;
import com.xkcyy.one.entity.Training;
import com.xkcyy.one.entity.TrainingExample;
import com.xkcyy.one.entity.TrainingSession;
import com.xkcyy.one.entity.TrainingLog;
import com.xkcyy.one.exception.BusinessException;
import com.xkcyy.one.mapper.TrainingExampleMapper;
import com.xkcyy.one.mapper.TrainingMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 训练服务类
 */
@Service
public class TrainingService {
    
    private final TrainingMapper trainingMapper;
    private final TrainingExampleMapper trainingExampleMapper;
    private final AgentService agentService;
    private final TrainingSessionService trainingSessionService;
    private final TrainingExampleService trainingExampleService;
    private final TrainingLogService trainingLogService;
    
    @Autowired
    public TrainingService(
            TrainingMapper trainingMapper,
            TrainingExampleMapper trainingExampleMapper,
            AgentService agentService,
            TrainingSessionService trainingSessionService,
            TrainingExampleService trainingExampleService,
            TrainingLogService trainingLogService) {
        this.trainingMapper = trainingMapper;
        this.trainingExampleMapper = trainingExampleMapper;
        this.agentService = agentService;
        this.trainingSessionService = trainingSessionService;
        this.trainingExampleService = trainingExampleService;
        this.trainingLogService = trainingLogService;
    }
    
    /**
     * 获取所有训练
     *
     * @return 训练列表
     */
    public List<Training> getAllTrainings() {
        return trainingMapper.selectList(null);
    }
    
    /**
     * 根据智能体ID获取训练列表
     *
     * @param agentId 智能体ID
     * @return 训练列表
     */
    public List<Training> getTrainingsByAgentId(Long agentId) {
        LambdaQueryWrapper<Training> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Training::getAgentId, agentId);
        return trainingMapper.selectList(queryWrapper);
    }
    
    /**
     * 根据ID获取训练
     *
     * @param id 训练ID
     * @return 训练
     */
    public Training getTrainingById(Long id) {
        Training training = trainingMapper.selectById(id);
        if (training == null) {
            throw new BusinessException("训练不存在，ID: " + id);
        }
        return training;
    }
    
    /**
     * 创建训练
     *
     * @param training 训练
     * @return 创建后的训练
     */
    @Transactional
    public Training createTraining(Training training) {
        // 检查智能体是否存在
        Agent agent = agentService.getAgentById(training.getAgentId());
        
        // 检查智能体是否可训练
        if (!agent.getTrainable()) {
            throw new BusinessException("智能体不可训练: " + agent.getName());
        }
        
        // 设置原始提示词为智能体的系统提示词
        training.setOriginalPrompt(agent.getSystemPrompt());
        
        // 设置默认值
        training.setStatus("PENDING");
        training.setMaxIterations(training.getMaxIterations() == null ? 5 : training.getMaxIterations());
        training.setCurrentIteration(0);
        
        // 设置创建时间和更新时间
        LocalDateTime now = LocalDateTime.now();
        training.setCreateTime(now);
        training.setUpdateTime(now);
        
        // 插入训练
        trainingMapper.insert(training);
        
        return training;
    }
    
    /**
     * 更新训练
     *
     * @param training 训练
     * @return 更新后的训练
     */
    public Training updateTraining(Training training) {
        // 检查训练是否存在
        Training existingTraining = trainingMapper.selectById(training.getId());
        if (existingTraining == null) {
            throw new BusinessException("训练不存在，ID: " + training.getId());
        }
        
        // 不允许修改智能体ID和原始提示词
        training.setAgentId(existingTraining.getAgentId());
        training.setOriginalPrompt(existingTraining.getOriginalPrompt());
        
        // 设置更新时间
        training.setUpdateTime(LocalDateTime.now());
        
        // 更新训练
        trainingMapper.updateById(training);
        
        return training;
    }
    
    /**
     * 删除训练
     *
     * @param id 训练ID
     */
    @Transactional
    public void deleteTraining(Long id) {
        // 检查训练是否存在
        Training existingTraining = trainingMapper.selectById(id);
        if (existingTraining == null) {
            throw new BusinessException("训练不存在，ID: " + id);
        }
        
        // 删除相关的训练样例
        LambdaQueryWrapper<TrainingExample> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrainingExample::getTrainingId, id);
        trainingExampleMapper.delete(queryWrapper);
        
        // 删除训练
        trainingMapper.deleteById(id);
    }
    
    /**
     * 更新训练状态
     *
     * @param id     训练ID
     * @param status 新状态
     * @return 更新后的训练
     */
    public Training updateTrainingStatus(Long id, String status) {
        Training training = trainingMapper.selectById(id);
        if (training == null) {
            throw new BusinessException("训练不存在，ID: " + id);
        }
        
        training.setStatus(status);
        training.setUpdateTime(LocalDateTime.now());
        trainingMapper.updateById(training);
        
        return training;
    }
    
    /**
     * 开始训练
     * 
     * @param id 训练ID
     * @return 更新后的训练
     */
    @Transactional
    public Training startTraining(Long id) {
        Training training = trainingMapper.selectById(id);
        if (training == null) {
            throw new BusinessException("训练不存在，ID: " + id);
        }
        
        // 检查训练状态
        if (!"PENDING".equals(training.getStatus()) && !"FAILED".equals(training.getStatus())) {
            throw new BusinessException("训练状态不允许开始: " + training.getStatus());
        }
        
        // 检查是否有训练样例
        LambdaQueryWrapper<TrainingExample> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrainingExample::getTrainingId, id);
        long exampleCount = trainingExampleMapper.selectCount(queryWrapper);
        if (exampleCount == 0) {
            throw new BusinessException("训练没有样例数据，无法开始训练");
        }
        
        // 更新训练状态
        training.setStatus("RUNNING");
        training.setUpdateTime(LocalDateTime.now());
        trainingMapper.updateById(training);
        
        // 异步执行训练过程
        executeTrainingAsync(id);
        
        return training;
    }
    
    /**
     * 异步执行训练过程
     * 
     * @param trainingId 训练ID
     */
    @Async
    protected CompletableFuture<Void> executeTrainingAsync(Long trainingId) {
        try {
            Training training = trainingMapper.selectById(trainingId);
            if (training == null) {
                return CompletableFuture.completedFuture(null);
            }
            
            // 获取训练样例
            List<TrainingExample> examples = trainingExampleService.getExamplesByTrainingId(trainingId);
            
            // 初始提示词为智能体的系统提示词
            String currentPrompt = training.getOriginalPrompt();
            
            // 执行迭代训练
            int maxIterations = training.getMaxIterations();
            for (int i = 1; i <= maxIterations; i++) {
                // 创建训练会话
                TrainingSession session = new TrainingSession();
                session.setTrainingId(trainingId);
                session.setPrompt(currentPrompt);
                session = trainingSessionService.createSession(session);
                
                // 处理每个训练样例
                float totalSimilarity = 0f;
                long startTime = System.currentTimeMillis();
                
                for (TrainingExample example : examples) {
                    // 使用当前提示词生成回复
                    String actualOutput = generateOutput(currentPrompt, example.getInput());
                    
                    // 计算相似度
                    float similarity = calculateSimilarity(actualOutput, example.getExpectedOutput());
                    totalSimilarity += similarity;
                    
                    // 记录训练日志
                    TrainingLog log = new TrainingLog();
                    log.setSessionId(session.getId());
                    log.setExampleId(example.getId());
                    log.setInput(example.getInput());
                    log.setExpectedOutput(example.getExpectedOutput());
                    log.setActualOutput(actualOutput);
                    log.setSimilarity(similarity);
                    trainingLogService.createLog(log);
                }
                
                // 计算性能指标
                float accuracy = totalSimilarity / examples.size();
                float responseTime = (System.currentTimeMillis() - startTime) / 1000.0f;
                float promptEfficiency = calculatePromptEfficiency(currentPrompt, accuracy);
                
                // 优化提示词
                String optimizedPrompt = optimizePrompt(currentPrompt, examples, trainingLogService.getLogsBySessionId(session.getId()));
                
                // 完成会话并更新指标
                trainingSessionService.completeSession(session.getId(), accuracy, responseTime, promptEfficiency);
                
                // 更新优化后的提示词
                trainingSessionService.updateSessionPrompt(session.getId(), optimizedPrompt);
                
                // 更新当前提示词用于下一轮迭代
                currentPrompt = optimizedPrompt;
                
                // 如果准确度已经很高，可以提前结束迭代
                if (accuracy > 0.95) {
                    break;
                }
            }
            
            // 完成训练
            training.setStatus("COMPLETED");
            training.setUpdateTime(LocalDateTime.now());
            trainingMapper.updateById(training);
            
            return CompletableFuture.completedFuture(null);
        } catch (Exception e) {
            // 更新训练状态为失败
            Training training = trainingMapper.selectById(trainingId);
            if (training != null) {
                training.setStatus("FAILED");
                training.setUpdateTime(LocalDateTime.now());
                trainingMapper.updateById(training);
            }
            return CompletableFuture.failedFuture(e);
        }
    }
    
    /**
     * 使用当前提示词生成输出
     * 实际中应调用大语言模型API
     * 
     * @param prompt 提示词
     * @param input 用户输入
     * @return 生成的输出
     */
    private String generateOutput(String prompt, String input) {
        // TODO: 调用大语言模型API，如OpenAI、Claude等
        // 这里仅为示例实现
        return "这是使用提示词生成的输出，针对输入: " + input;
    }
    
    /**
     * 计算实际输出与期望输出的相似度
     * 
     * @param actual 实际输出
     * @param expected 期望输出
     * @return 相似度(0-1)
     */
    private float calculateSimilarity(String actual, String expected) {
        // TODO: 实现文本相似度算法，如余弦相似度、BLEU等
        // 这里仅为示例实现
        return 0.8f;
    }
    
    /**
     * 计算提示词效率指标
     * 
     * @param prompt 提示词
     * @param accuracy 准确度
     * @return 效率指标
     */
    private float calculatePromptEfficiency(String prompt, float accuracy) {
        // 效率 = 准确度 / (提示词长度的平方根)
        return (float) (accuracy / Math.sqrt(prompt.length()) * 100);
    }
    
    /**
     * 优化提示词
     * 
     * @param currentPrompt 当前提示词
     * @param examples 训练样例列表
     * @param logs 当前会话的训练日志
     * @return 优化后的提示词
     */
    private String optimizePrompt(String currentPrompt, List<TrainingExample> examples, List<TrainingLog> logs) {
        // TODO: 实现提示词优化算法
        // 这里仅为示例实现
        return currentPrompt + "\n请注意准确理解用户意图，提供精确回答。";
    }
    
    /**
     * 应用训练结果到智能体
     *
     * @param id 训练ID
     * @return 更新后的智能体
     */
    @Transactional
    public Agent applyTrainingResult(Long id) {
        Training training = trainingMapper.selectById(id);
        if (training == null) {
            throw new BusinessException("训练不存在，ID: " + id);
        }
        
        // 检查训练是否已完成
        if (!"COMPLETED".equals(training.getStatus())) {
            throw new BusinessException("训练未完成，无法应用结果");
        }
        
        // 检查是否有优化后的提示词
        if (training.getOptimizedPrompt() == null || training.getOptimizedPrompt().isEmpty()) {
            throw new BusinessException("训练未产生优化提示词，无法应用结果");
        }
        
        // 更新智能体的系统提示词
        return agentService.updateAgentSystemPrompt(training.getAgentId(), training.getOptimizedPrompt());
    }
} 